#include "treedraw.h"
#include "qgl.h"
#include "math.h"
#include "qglshaderprogram.h"
#include <QFile>
using namespace std;

#define PI 3.14
TreeDraw::TreeDraw(){
    mQuadric = gluNewQuadric();

}

void TreeDraw::drawTree(TreeGen2D *treeGen){
    leaf = this->loadTexture("/home/bcheung/course/cs224Final/cs224-trees/textures/leaf.png");

    recurDraw(treeGen->treeRoot);
    recurDrawLeaf(treeGen->treeRoot);
}

void TreeDraw::recurDrawLeaf(Bud *bud){
    if(!bud->aux || !bud->term)
        drawLeaf(bud);
    if (bud->aux) recurDrawLeaf(bud->aux);
    if (bud->term) recurDrawLeaf(bud->term);
}

void TreeDraw::recurDraw(Bud *bud){
    drawInterNode(bud);
    drawBud(bud);
    //drawLeaf(bud);
    if (bud->aux) recurDraw(bud->aux);
    if (bud->term) recurDraw(bud->term);
}

void TreeDraw::animateTree(){}
//store cumulative transformations
//let's call y height
void TreeDraw::drawInterNode(Bud *bud){
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glColor3f(0.3, 0.3, 0.3);

    float xoff = bud->diameter/2.0 * +sin(bud->theta);
    float yoff = bud->diameter/2.0 * -cos(bud->theta);
    //xoff = bud->diameter / 2.0;
    //yoff = 0;
    glBegin(GL_QUADS);
        glVertex2f(bud->start.x - xoff, bud->start.y - yoff);
        glVertex2f(bud->start.x + xoff, bud->start.y + yoff );
        glVertex2f(bud->end.x + xoff, bud->end.y + yoff);
        glVertex2f(bud->end.x - xoff, bud->end.y - yoff);
    glEnd();

    if(bud->aux){
        float tx = bud->aux->diameter/2.0 * +sin(bud->aux->theta);
        float ty = bud->aux->diameter/2.0 * -cos(bud->aux->theta);
        glBegin(GL_TRIANGLES);
        glVertex2f(bud->end.x - xoff, bud->end.y - yoff);
        glVertex2f(bud->end.x + xoff, bud->end.y + yoff);
        glVertex2f(bud->aux->start.x - tx, bud->aux->start.y - ty);

        glVertex2f(bud->end.x - xoff, bud->end.y - yoff);
        glVertex2f(bud->end.x + xoff, bud->end.y + yoff);
        glVertex2f(bud->aux->start.x + tx, bud->aux->start.y + ty);

        glEnd();
    }

    if(bud->term){
        float tx = bud->term->diameter/2.0 * +sin(bud->term->theta);
        float ty = bud->term->diameter/2.0 * -cos(bud->term->theta);
        glBegin(GL_TRIANGLES);
        glVertex2f(bud->end.x - xoff, bud->end.y - yoff);
        glVertex2f(bud->end.x + xoff, bud->end.y + yoff);
        glVertex2f(bud->term->start.x - tx, bud->term->start.y - ty);

        glVertex2f(bud->end.x - xoff, bud->end.y - yoff);
        glVertex2f(bud->end.x + xoff, bud->end.y + yoff);
        glVertex2f(bud->term->start.x + tx, bud->term->start.y + ty);

        glEnd();
    }
}
void TreeDraw::drawLeaf(Bud *bud){

        bool flip = bud->auxDir.x <0;
        m_leaf->bind();

        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glPushMatrix();
        glTranslatef(bud->end.x, bud->end.y, bud->end.z);
        glTranslatef(-2*bud->direction.x, -2*bud->direction.y, 0);
        if(!flip) glTranslatef(-bud->diameter/2.0,0,0);
        else glTranslatef(bud->diameter/2.0,0,0);
        //glRotatef((bud->theta +bud->auxAngle*2) *180.0/PI,0,0,1);
        glScalef(15,15,1);

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,leaf);
        glBegin(GL_QUADS);
            if(flip) glTexCoord3f(1,0,bud->darken);
            else glTexCoord3f(0,0,bud->darken);
            glVertex2f(-.5, -.5);

            if(flip) glTexCoord3f(0,0,bud->darken);
            else glTexCoord3f(1,0,bud->darken);
            glVertex2f(.5,-.5);

            if(flip) glTexCoord3f(0,1,bud->darken);
            else glTexCoord3f(1,1,bud->darken);
            glVertex2f(.5,.5);

            if(flip) glTexCoord3f(1,1,bud->darken);
            else glTexCoord3f(0,1,bud->darken);
            glVertex2f(-.5,.5);

        glEnd();
        glDisable(GL_TEXTURE_2D);
        //gluDisk(mQuadric, 0, bud->diameter/2.0, 10, 10);
        glPopMatrix();
        m_leaf->release();

}

void TreeDraw:: drawBud(Bud *bud)
{
    if(!bud->aux){
        // draw auxilarly bud if there is no auxilary node
        glColor3f(0, .5, 0);
        glPushMatrix();
        glTranslatef(bud->end.x, bud->end.y, bud->end.z);
        glTranslatef(-2*bud->direction.x, -2*bud->direction.y, 0);
        glRotatef((bud->theta +bud->auxAngle) *180.0/PI,0,0,1);
        glTranslatef(1,0,0);
        glBegin(GL_TRIANGLE_FAN);
        glVertex2f(0, 0);
        for(float angle = 0; angle<= 360; angle += 10){
            glVertex2f(cos(angle*PI/180.0)*1.3, sin(angle*PI/180.0)*.7);
        }
        glEnd();
        //gluDisk(mQuadric, 0, bud->diameter/2.0, 10, 10);
        glPopMatrix();

    }
    if(!bud->term){
        // draw terminal bud if there is no terminal node

        //temporarily the terminal bud is a circle of radius 2, centered about the
        //end of the bud internode
        glColor3f(0, .8, 0);
        glPushMatrix();
        glTranslatef(bud->end.x, bud->end.y, bud->end.z);
        glRotatef(bud->theta *180.0/PI,0,0,1);
        glBegin(GL_TRIANGLE_FAN);
        glVertex2f(0, 0);
        for(float angle = 0; angle<= 360; angle += 10){
            glVertex2f(2.3*cos(angle*PI/180.0)*bud->diameter/2.0, sin(angle*PI/180.0)*bud->diameter/2.0);
        }
        glEnd();
        //gluDisk(mQuadric, 0, bud->diameter/2.0, 10, 10);
        glPopMatrix();
    }
}
void TreeDraw::drawFlower(){}

GLuint TreeDraw::loadTexture(const QString &filename) {
    QImage image, texture;
    QFile file(filename);
    GLuint toReturn;
    if(!file.exists()){
        std::cout << "Failed to load texture: " << file.fileName().toStdString() << std::endl;
        return -1;
    }
    image.load(file.fileName());
   // image = image.mirrored(true, false);
    texture = QGLWidget::convertToGLFormat(image);
    glGenTextures(1, &toReturn);
    glBindTexture(GL_TEXTURE_2D, toReturn);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, texture.width(), texture.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
    //gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texture.width(), texture.height(), GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

    return toReturn;

}
